package com.centerm.bluetooth.core.controller;

import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.util.ArrayMap;

import com.centerm.bluetooth.core.controller.constants.BluetoothState;
import com.centerm.bluetooth.core.controller.constants.Constants;
import com.centerm.bluetooth.core.listener.IBluetoothDataReceiveListener;
import com.centerm.bluetooth.core.listener.IBluetoothFoundListener;
import com.centerm.bluetooth.core.listener.IBluetoothStateListener;
import com.centerm.bluetooth.ibridge.BluetoothIBridgeAdapter;
import com.centerm.bluetooth.ibridge.BluetoothIBridgeDevice;
import com.centerm.bluetooth.ibridge.constants.ChannelConfig;
import com.centerm.bluetooth.ibridge.listener.DataReceiver;
import com.centerm.bluetooth.ibridge.listener.EventReceiver;
import com.centerm.bluetooth.model.Respond;
import com.centerm.bluetooth.model.RespondStatus;
import com.centerm.util.HexUtil;
import com.centerm.util.Logger;

import java.io.IOException;

/**
 * Created by linwenhui on 2017/2/9.
 * 蓝牙控制类
 */
public class BluetoothController {

    private final static String TAG = "BluetoothController";
    //包序号
    private byte packageId;
    private BluetoothIBridgeAdapter mAdapter;
    private static BluetoothController instance;
    private Context context;

    //发送指令
    private byte[] cmd;
    private BluetoothIBridgeDevice curDevice;
    //蓝牙数据接收器
    private ArrayMap<Byte, IBluetoothDataReceiveListener> mBluetoothListeners;
    //蓝牙信号搜索回调
    private IBluetoothFoundListener mBluetoothFoundListener;
    //蓝牙设备连接状态
    private IBluetoothStateListener mBluetoothStateListener;

    private BluetoothController(@NonNull Context context) {
        this.context = context;
        mAdapter = BluetoothIBridgeAdapter.getDefaultAdapter(context);
        mAdapter.setAutoBondBeforConnect(true);
        mAdapter.setAutoWritePincode(true);
        mAdapter.setPincode("0000");
        mAdapter.registerDataReceiver(new DataReceiverImp());
        mAdapter.registerEventReceiver(new EventReceiverImp());
        mBluetoothListeners = new ArrayMap<>();
    }

    public synchronized void destroy() {
        mAdapter.destroy();
    }

    public static BluetoothController getInstance(@NonNull Context context) {
        if (instance == null) {
            synchronized (BluetoothController.class) {
                if (instance == null)
                    instance = new BluetoothController(context);
            }
        }
        return instance;
    }

    /**
     * 注册蓝牙数据 监听
     *
     * @param bluetoothListener
     */
    public synchronized void registerBluetoothListener(byte key, @NonNull IBluetoothDataReceiveListener bluetoothListener) {
        if (!mBluetoothListeners.containsKey(key))
            mBluetoothListeners.put(key, bluetoothListener);
    }

    /**
     * 取消蓝牙数据监听
     *
     * @param key
     */
    public synchronized void unRegisterBluetoothListener(byte key) {
        if (mBluetoothListeners.containsKey(key))
            mBluetoothListeners.remove(key);
    }

    /**
     * 蓝牙搜索回调
     *
     * @param mBluetoothFoundListener
     */
    public void setBluetoothFoundListener(@NonNull IBluetoothFoundListener mBluetoothFoundListener) {
        this.mBluetoothFoundListener = mBluetoothFoundListener;
    }

    /**
     * 蓝牙连接状态回调
     *
     * @param mBluetoothStateListener
     */
    public void setBluetoothStateListener(@NonNull IBluetoothStateListener mBluetoothStateListener) {
        this.mBluetoothStateListener = mBluetoothStateListener;
    }

    /**
     * 向蓝牙当前连接的蓝牙设备发送数据
     *
     * @param cmd
     * @param params
     * @throws IOException
     */
    public synchronized boolean send(@NonNull byte[] cmd, byte[] params) throws IOException {
        if (curDevice != null && curDevice.isConnected()) {
            packageId++;
            if (packageId > 0xFF) {
                packageId = 1;
            }
            this.cmd = cmd;
            final byte[] requestData = ChannelConfig.requestPack(packageId, cmd, params);
            Logger.i(TAG, "上送解析报文:");
            Logger.i(TAG, requestData, Logger.TYPE.CODE16);
            Logger.i(TAG, "mAdapter.send");
            mAdapter.send(curDevice, requestData, requestData.length);
            Logger.i(TAG, "上送完成");
            return true;
        }
        return false;
    }

    public synchronized void connect(@NonNull BluetoothIBridgeDevice device) {
        if (mBluetoothStateListener != null) {
            mBluetoothStateListener.onBluetoothStateChange(BluetoothState.CONNECTTING);
        }
        mAdapter.connect(device);
    }

    public synchronized void disconnect(@NonNull BluetoothIBridgeDevice device) {
        mAdapter.disconnect(device);
    }

    public void startDiscovery() {
        mAdapter.startDiscovery();
    }

    public void stopDiscovery() {
        mAdapter.stopDiscovery();
    }

    /**
     * 蓝牙数据接收
     */
    private class DataReceiverImp implements DataReceiver {

        @Override
        public void onDataReceived(BluetoothIBridgeDevice device, byte[] bytes, int length) {
            Logger.i(TAG, " == onDataReceived == ");
            if (bytes != null) {
                Logger.i(TAG, "收到蓝牙" + device.getDeviceName() + "发送来的数据，长度为" + length
                        + ",数据内容为");
                Logger.i(TAG, bytes, Logger.TYPE.CODE16);
                final Respond respond = ChannelConfig.respondParse(packageId, bytes, cmd);
                if (respond == null)
                    return;
                Logger.i(respond);
                final int len = mBluetoothListeners.size();
                Logger.i(" == len == " + len);
                if (respond.getRespondStatus() == RespondStatus.OK) {
                    Logger.i(respond.getContent(), Logger.TYPE.CODE16);
                    if (respond.getType() == Respond.RESPOND) {
                        byte cmdFlag = (byte) (respond.getCmd()[0] & 0xFF);
                        if (mBluetoothListeners.containsKey(cmdFlag)) {
                            IBluetoothDataReceiveListener bluetoothDataReceiveListener = mBluetoothListeners.get(cmdFlag);
                            if (bluetoothDataReceiveListener != null)
                                bluetoothDataReceiveListener.onDataReceived(device, respond);
                        }
                    } else if (respond.getType() == Respond.NOTICE) {
                        byte[] params = respond.getContent();
                        byte[] cmdBytes = new byte[]{params[0], params[1]};
                        Intent intent = new Intent();
                        final String action = Constants.CMD_ACTION + HexUtil.byte2HexStr(cmdBytes);
                        Logger.i(" == action == ", action);
                        intent.setAction(action);
                        if (params.length > 2) {
                            byte[] realParams = new byte[params.length - 2];
                            System.arraycopy(params, 2, realParams, 0, realParams.length);
                            intent.putExtra(Constants.PARAMS, realParams);
                            Logger.i(realParams, Logger.TYPE.CODE16);
                        }
                        intent.putExtra(Constants.ALL_PARAMS, respond.getAllPackageData());
                        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
                    }
                } else {
                    byte cmdFlag = (byte) (respond.getCmd()[0] & 0xFF);
                    if (mBluetoothListeners.containsKey(cmdFlag)) {
                        IBluetoothDataReceiveListener bluetoothDataReceiveListener = mBluetoothListeners.get(cmdFlag);
                        if (bluetoothDataReceiveListener != null)
                            bluetoothDataReceiveListener.onDataReceivedError(device, respond);
                    }
                }

            }
        }
    }

    private class EventReceiverImp implements EventReceiver {

        @Override
        public void onDiscoveryFinished() {
            if (mBluetoothFoundListener != null)
                mBluetoothFoundListener.onDiscoveryFinished();
        }

        @Override
        public void onDeviceFound(BluetoothIBridgeDevice device) {
            if (mBluetoothFoundListener != null)
                mBluetoothFoundListener.onDeviceFound(device);
        }

        @Override
        public void onDeviceBonded(BluetoothIBridgeDevice device) {
        }

        @Override
        public void onDeviceConnected(BluetoothIBridgeDevice device) {
            curDevice = device;
            if (mBluetoothStateListener != null) {
                mBluetoothStateListener.onBluetoothStateChange(BluetoothState.CONNECTED);
            }
        }

        @Override
        public void onDeviceDisconnected(BluetoothIBridgeDevice device, String exceptionMsg) {
            if (mBluetoothStateListener != null) {
                mBluetoothStateListener.onBluetoothStateChange(BluetoothState.DISCONNECTED);
            }
        }

        @Override
        public void onDeviceConnectFailed(BluetoothIBridgeDevice device, String exceptionMsg) {
            if (mBluetoothStateListener != null) {
                mBluetoothStateListener.onBluetoothStateChange(BluetoothState.CONNECT_LOST);
            }
        }

        @Override
        public void onWriteFailed(BluetoothIBridgeDevice device, String exceptionMsg) {

        }
    }
}
